#include <stdio.h>
#include <arpa/inet.h>
#include <omp.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>


void func_help(){
  fprintf(stderr,"Utilisation\n");
  fprintf(stderr,"main [-a IPv4 | -n Netmask]\n");
  fprintf(stderr,"-a IPv4:\tStarting ipv4 address\n");
  fprintf(stderr,"-n Netmask:\tNetmask to use\n");
  return;
}
 
 
int scan_ip(struct in_addr ip, struct in_addr mask){
        struct in_addr broadcast,reseau,currentIP;
        reseau.s_addr = ip.s_addr & mask.s_addr;
        broadcast.s_addr = reseau.s_addr | ~mask.s_addr;
 
#ifdef DEBUG
        fprintf(stderr,"Debug Mode: \n");
        fprintf(stderr,"\tIPv4      : %s \n", inet_ntoa(ip));
        fprintf(stderr,"\tMasque    : %s \n", inet_ntoa(mask));
        fprintf(stderr,"\tRéseau    : %s \n", inet_ntoa(reseau));
        fprintf(stderr,"\tBroadcast : %s \n", inet_ntoa(broadcast));
#ifdef _OPENMP
	fprintf(stderr,"\tOpenMP    : oui \n");
#else
	fprintf(stderr,"\tOpenMP    : non \n");
#endif
#endif

#pragma omp parallel for
        for(currentIP = reseau;currentIP.s_addr < broadcast.s_addr; currentIP.s_addr = htonl(ntohl(currentIP.s_addr)+1)){
#ifdef _OPENMP
                printf("Thread %i, IPv4: %s \n",omp_get_num_threads(), inet_ntoa(currentIP));
#else
                printf("IPv4 %s\n", inet_ntoa(currentIP));
#endif
        }
        return 0;
}
 
int main (int argc, char * argv[]) {
  struct timeval ti,tf;
  struct in_addr ip,masque;

#ifdef _OPENMP
        omp_set_dynamic(0);
#endif

 
  char format[] = "ha:n:";
  int optch;
  extern int opterr;
  char * ip_buff;
  char * netmask_buff;
  int ip_set=0,netmask_set=0;

  opterr = 1;

  while((optch = getopt(argc, argv, format)) != -1)
    switch(optch) {
      case 'a':
        ip_buff = optarg;
        ip_set = 1;
        break;
      case 'n':
        netmask_buff = optarg;
        netmask_set = 1;
        break;
      case 'h':
        func_help();
        return 0;
        break;
    }
        if (ip_set){
          ip.s_addr = inet_addr(ip_buff);
        } else {
          ip.s_addr = inet_addr("192.168.1.1");
        }
        if (netmask_set){
          masque.s_addr = inet_addr(netmask_buff);
        } else {
          masque.s_addr = inet_addr("255.255.255.0");
        }
        gettimeofday(&ti,NULL);
        scan_ip(ip, masque);
        gettimeofday(&tf,NULL);
 
        fprintf(stderr," Execution time  : %f micro secondes \n", ((double) ((tf.tv_sec-ti.tv_sec)*1000000 + (tf.tv_usec-ti.tv_usec))));
    return 0;
}

